/******************************************************************************\
    ContestDataBase.h discribes a database of contests.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include ".\BaseDataBase.hpp"

namespace nsContestDataBase
{
	const unsigned long FLAG_ENABLED          = 0x00000001ul;
	const unsigned long FLAG_FROZEN_ENABLED   = 0x00000002ul;
	const unsigned long FLAG_ITMO_RATING      = 0x00000004ul;
	const unsigned long FLAG_AFTERSUBMIT      = 0x00000008ul;

	const size_t MAX_TITLE_LENGTH = 255;
	const size_t MAX_COMMENT_LENGTH = 255;

	struct sContestData0
	{
		unsigned long Key;
		char Title[ MAX_TITLE_LENGTH + 1 ];
		char Comment[ MAX_COMMENT_LENGTH + 1 ];
		unsigned long Duration;
		bool IsEnabled;
		unsigned long FrozenTime;
		bool IsFrozenEnabled;
	};

	struct sContestData1
	{
		unsigned long Key;
		char Title[ MAX_TITLE_LENGTH + 1 ];
		char Comment[ MAX_COMMENT_LENGTH + 1 ];
		unsigned long Duration;
		unsigned long FrozenTime;
		unsigned long Flags;
		unsigned long Penalty;
	};

	typedef sContestData1 sContestData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] =
	{
		{ sizeof( sContestData0 ), sizeof( sContestData1 ), &ConversionFunction0 }
	};

	struct TitleCompare : public std::binary_function< cDataPointer< sContestData >, cDataPointer< sContestData >, bool >
	{
		bool operator()( const cDataPointer< sContestData > &left, const cDataPointer< sContestData > &right ) const
		{
			return _stricmp( left->Title, right->Title ) < 0;
		}
	};

	typedef cBaseDataBase< sContestData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sContestData, TitleCompare > TitleIterator;

	class cWardContestDataBase : public cBaseDataBase< sContestData >
	{
	private:
		std::set< cDataPointer< sContestData >, TitleCompare > TitleIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sContestData > &data_pointer )
		{
			return TitleIndex.find( data_pointer ) != TitleIndex.end();
		}
		virtual void InsertIndex( const cDataPointer< sContestData > &data_pointer )
		{
			TitleIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sContestData > &data_pointer, unsigned long index )
		{
			TitleIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sContestData > &data_pointer ) 
		{
			TitleIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			TitleIndex.clear();
		}
	public:
		cWardContestDataBase( /*bool auto_update*/ )
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		TitleIterator BeginByTitle() const
		{
			return TitleIterator( TitleIndex.begin() );
		}
		TitleIterator FindByTitle( const char title[] ) const
		{
			if( strlen( title ) > MAX_TITLE_LENGTH )
				return EndByTitle();
			sContestData contest_data;
			strcpy( contest_data.Title, title );
			return TitleIterator( TitleIndex.find( cDataPointer< sContestData >( &contest_data ) ) );
		}
		TitleIterator EndByTitle() const
		{
			return TitleIterator( TitleIndex.end() );
		}
	};

	class cContestDataBase : public cPointerObject< cWardContestDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardContestDataBase *ward_contest_data_base;
			try
			{
				ward_contest_data_base = new cWardContestDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_contest_data_base ) )
			{
				delete ward_contest_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
